#include "VarTable.h"
#include "Error.h"
#include <string>
#include <cstring>
#include <sstream>
#include <cassert>
//#include <iostream> // for clog
using namespace std;
VarTable* VarTable::instance = NULL;
VarTable::VarTable()
{
	memset(table, 0, sizeof(table));
}
VarTable::~VarTable()
{
	for (long i = 0; i < size; i++)
		if (table[i] != NULL)
		{
			delete table[i];
			table[i] = NULL;
		}
}
long VarTable::BKRDHash(const string& s) const
{
	int l = s.size();
	int seed = 131;
	long hash = 0;
	for (int i = 0; i < l; i++)
		hash = hash * seed + s[i];
	return (hash&0x7FFFFFFF)%size;
}
VarTable::node* VarTable::find(const string& s) const
{
	long hash = BKRDHash(s);
	node* p = table[hash];
	while (p != NULL)
	{
		if (p->id == s)
			return p;
		else
			p = p->next;
	}
	return NULL;//p;//WRONG!! Why?
}
/* marked right but I don't know why the simpler func above is wrong
dict::node* dict::find(const string& s) const
{
	long hash = BKRDHash(s);
	if (fre[hash] == NULL || fre[hash]->id == s)
		return fre[hash];
	else
	{
		node* q = fre[hash];
		node* p = q->next;
		while(p != NULL)
		{
			if (p->id == s)
				return q->next;
			q = p;
			p = q->next;
		}
		return q->next;
	}
}
*/
string VarTable::extractVarname(const string& rawname) const
{
	//clog << "EXTRACTING FROM " << rawname << "..." << endl;
	istringstream sin(rawname);
	string varname, word;
	sin >> varname >> word;
	if (varname.size() == 0)
		throw Error("Variable expected but not found.");
	else if (!('a' <= varname[0] && varname[0] <= 'z' || 'A' <= varname[0] && varname[0] <= 'Z' || varname[0] == '_'))
		throw Error("Invalid variable name (first letter): " + rawname + ".");
	else
	{
		for (int i = 1; i < varname.size(); i++)
			if (!('a' <= varname[i] && varname[i] <= 'z' || 'A' <= varname[i] && varname[i] <= 'Z' || varname[i] == '_' || '0' <= varname[i] && varname[i] <= '9'))
				throw Error("Invalid variable name (invalid character): " + rawname + ".");
	}
	sin >> word;
	if (word != "")
		throw Error("Unexpected \"" + word + "\" after variable.");
	//clog << "EXTRACTED: " << varname << "|||" << endl;
	return varname;
}

